/*package gm.open;
import gm._

object bla {
  def f[a](x:a):a = identity(x)
}

trait GenericComp requires (CoreConvsComp with GenericComp) {
  type TGeneric <: CGeneric
  type Generic[gg <: TypeFun1] = TGeneric{type g=gg}
  
  def Generic: TGeneric
  trait CGeneric requires TGeneric {
    type g <: TypeFun1
    
    def unit: app1[g, Unit]
    def plus[aa, b](implicit c1: aa=>Rep[aa], c2: b=>Rep[b]): app1[g, Plus[aa, b]]
    def pair[aa, b](implicit c1: aa=>Rep[aa], c2: b=>Rep[b]): app1[g, Pair[aa, b]]
    def datatype[repT, t](iso: Iso[repT, t])(implicit c1: repT=>Rep[repT]): app1[g, t]
    def char: app1[g, Char]
    def int: app1[g, Int]
  
    implicit val self = this
  }

  trait Rep[t] {           
    def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, t]
  }
  
  trait Plus[a,b]
    case class Inl[a,b](el: a) extends Plus[a,b]
    case class Inr[a,b](el: b) extends Plus[a,b]

  case class Iso[repT, t](fromData: t=>repT, toData: repT=>t)
}

trait CoreConvsComp requires (CoreConvsComp with GenericComp) {
  type XConvs <: CoreConvs;  
  def makeConvs: XConvs

  trait Convs {
    // TODO: requires higher-rank polymorphism
//    def RepI[t]([g <: TypeFun1] f: Generic[g]=>app1[g, t]) = new Rep[t]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, t]=f(gen)}    
  }

  trait CoreConvs requires XConvs extends Convs { 
    implicit def unit2rep(u: Unit): Rep[Unit] = new Rep[Unit]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Unit]= gen.unit }//  RepI (.unit)
    implicit def int2rep(i: Int): Rep[Int] = new Rep[Int]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Int]= gen.int } //RepI (.int)
    implicit def char2rep(c: Char): Rep[Char] = new Rep[Char]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Char]= gen.char } //RepI (.char)
    implicit def pair2rep[t, u](p: Pair[t, u])(implicit c1: t=>Rep[t], c2: u=>Rep[u]): Rep[Pair[t, u]] 
        = new Rep[Pair[t, u]]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Pair[t, u]]= gen.pair } //RepI (.pair(c1, c2)) // TODO: why do c1, c2 have to be passed explicitly? -- if I inline mr, it's not necessary
    implicit def plus2rep[t, u](p: Plus[t, u])(implicit c1: t=>Rep[t], c2: u=>Rep[u]): Rep[Plus[t, u]]  
        = new Rep[Plus[t, u]]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Plus[t, u]]= gen.plus } //RepI (.plus(c1, c2))
  }
}

trait ListConvComp requires (CoreConvsComp with ListConvComp with GenericComp) {
  type XConvs <: (CoreConvs with ListConv)
  
  trait ListConv requires XConvs extends Convs {
    def fromList[t](l: List[t]): Plus[Unit, Pair[t, List[t]]] = l match {
      case Nil => Inl(())
      case x :: xs => Inr(Pair(x, xs))
    }
    
    def toList[t](l: Plus[Unit, Pair[t, List[t]]]): List[t] = l match {
      case Inl(())=> Nil 
      case Inr(Pair(x, xs)) => x :: xs 
    }
    
    implicit def list2rep[t](l: List[t])(implicit c: t=>Rep[t]): Rep[List[t]] 
      = new Rep[List[t]]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, List[t]]= gen.datatype(Iso(fromList[t], toList[t])) } //RepI (.datatype(Iso(fromList[t], toList[t])))  // TODO: have to supply [t], why?
  }     
}

trait TraverseComp requires (CoreConvsComp with GenericComp with TraverseComp) {
  type TGeneric <: CGeneric with TraverseTC 
  
  trait TraverseTC requires TGeneric {
    type g = Traverse
    def unit = Traverse ((x: Unit) => x) 
    def plus[a, b](implicit c1: a=>Rep[a], c2: b=>Rep[b]) = Traverse[Plus[a, b]] (
        (x: Plus[a, b]) => x match {
          case Inl(el) => Inl(traverse(el))
          case Inr(el) => Inr(traverse(el))
        }) 
    
    def pair[a, b](implicit c1: a=>Rep[a], c2: b=>Rep[b]) = Traverse (
        (x: Pair[a, b]) => Pair(traverse(x._1), traverse(x._2)))
    
    def datatype[a, b](iso: Iso[a,b])(implicit c1: a=>Rep[a]) = Traverse (
        (x: b) => iso.toData(traverse(iso.fromData(x))))
    
    def char = Traverse ((x: Char) => x)
    def int = Traverse ((x: Int) => x)

    def traverse[t](x: t)(implicit c: t=>Rep[t]): t = x.rep(this).apply(x) // TODO why isn't arg to rep inferred?
  }
  
  def Traverse[aa](f: aa => aa) = new Traverse{type a=aa; val apply = f} 
  trait Traverse extends TypeFun1{ val apply: a => a }
}

//trait ASTComp {
  trait Term 
   case class Name(name: String) extends Term
   case class LocalVal(name: String, tpe: Option[Type], value :Term, scope: Term) extends Term 

  trait Type
   case class Inst (e: Term) extends Type
//}

trait ASTConvComp requires (CoreConvsComp with ListConvComp with GenericComp with ASTConvComp) {
  type XConvs <: (CoreConvs with ListConv with ASTConv)
  
  trait ASTConv requires XConvs extends CoreConvs {
    def fromTerm(t: Term): Plus[List[Char], Pair[List[Char], Pair[Option[Type], Pair[Term, Term]]]] = t match {
      case Name(name) => Inl(name.toList)
      case LocalVal(name, tpe, value, scope) => Inr(Pair(name.toList, Pair(tpe, Pair(value, scope))))
    }
  
    def toTerm(tr: Plus[List[Char], Pair[List[Char], Pair[Option[Type], Pair[Term, Term]]]]): Term = tr match {
      case Inl(name) => Name(name.toString) 
      case Inr(Pair(name, Pair(tpe, Pair(value, scope)))) => LocalVal(name.toString, tpe, value, scope) 
    }
  
    implicit def term2rep(t: Term): Rep[Term] 
      = new Rep[Term]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Term]= gen.datatype(Iso(fromTerm, toTerm)) }

    def fromType(t: Type): Term = t match {
      case Inst (e) => e
    }

    def toType(tr: Term): Type = Inst(tr)

    implicit def type2rep(t: Type): Rep[Type] 
      = new Rep[Type]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Type]= gen.datatype(Iso(fromType, toType)) }

    def fromOption[s](o: Option[s]): Plus[s, Unit] = o match {
      case Some(e) => Inl(e)
      case None => Inr(())
    }

    def toOption[s](or: Plus[s, Unit]): Option[s] = or match {
      case Inl(e) => Some(e)
      case Inr(()) => None
    }

    implicit def option2rep[t,u](t: Option[u])(implicit c: u=>Rep[u]): Rep[Option[u]] 
      = new Rep[Option[u]]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Option[u]]= gen.datatype(Iso(fromOption[u], toOption[u])) }
  }     
}

trait CustomASTConvComp requires (CoreConvsComp with GenericComp with CustomASTGenericComp with CustomASTConvComp) {
  type XConvs <: (CoreConvs with SubstASTConv)
  
  trait SubstASTConv requires XConvs extends Convs {
    implicit def term2rep(t: Term): Rep[Term] 
      = new Rep[Term]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Term]= gen.term }
    implicit def type2rep(lv: Type): Rep[Type] 
      = new Rep[Type]{def rep[g <: TypeFun1](implicit gen: Generic[g]): app1[g, Type]= gen.tpe }  
  }     
}

trait CustomASTGenericComp requires (CoreConvsComp with GenericComp with CustomASTGenericComp) {
  type TGeneric <: CGeneric with CSubstASTGeneric
  
  trait CSubstASTGeneric requires TGeneric {
    def term: app1[g, Term]
    def tpe: app1[g, Type]
  }
}


trait SubstASTComp requires (CoreConvsComp with GenericComp with CustomASTGenericComp with SubstASTComp) {
  type TGeneric <: CGeneric with SubstASTTC 
  
  trait SubstASTTC requires TGeneric {
    type g = SubstAST
    def unit = SubstAST ((x: Unit) => x) 
    def plus[a, b](implicit c1: a=>Rep[a], c2: b=>Rep[b]) = SubstAST[Plus[a, b]] (
        (x: Plus[a, b]) => x match {
          case Inl(el) => Inl(substAST(el))
          case Inr(el) => Inr(substAST(el))
        }) 
    
    def pair[a, b](implicit c1: a=>Rep[a], c2: b=>Rep[b]) = SubstAST (
        (x: Pair[a, b]) => Pair(substAST(x._1), substAST(x._2)))
    
    def datatype[a, b](iso: Iso[a,b])(implicit c1: a=>Rep[a]) = SubstAST (
        (x: b) => iso.toData(substAST(iso.fromData(x))))
    
    def char = SubstAST ((x: Char) => x)
    def int = SubstAST ((x: Int) => x)
    

    def substAST[t](x: t)(implicit c: t=>Rep[t]): t = x.rep(this).apply(x) // TODO why isn't arg to rep inferred?
  }
  
  def SubstAST[aa](f: aa => aa) = new SubstAST{type a=aa; val apply = f} 
  trait SubstAST extends TypeFun1{ val apply: a => a }
}


object deploy extends TypeFuns with GenericComp with CoreConvsComp with ListConvComp with TraverseComp with ASTConvComp{
  type XConvs = CoreConvs with ListConv with ASTConv
  def makeConvs = new CoreConvs with ListConv with ASTConv
  
  class MyTraversal requires TGeneric  extends  CGeneric with TraverseTC{
    override def char = Traverse ((x: Char) => 'c') // TODO: bug? override should take self type in consideration
  }
  
  type TGeneric = CGeneric with TraverseTC with MyTraversal
  def Generic = new  MyTraversal
  val term: Term = LocalVal("a", Some(Inst(Name("ccc"))), Name("bb"), Name("eeee"))
  val gen = Generic; val c= makeConvs; import c._; 
  val r = gen.traverse(term) // every letter becomes a 'c'
}

// use default sum-of-products view, except for names and localvals... TODO!
object deploySubst extends Application with TypeFuns with GenericComp with CoreConvsComp with ListConvComp  with CustomASTConvComp with CustomASTGenericComp with SubstASTComp {
  type XConvs = CoreConvs with ListConv with SubstASTConv
  def makeConvs = new CoreConvs with ListConv with SubstASTConv
  
  object FineGrained extends  GenericComp with CoreConvsComp with ListConvComp  with CustomASTGenericComp with ASTConvComp {
    type XConvs = CoreConvs with ListConv with ASTConv
    type TGeneric = deploySubst.TGeneric
    def Generic = deploySubst.Generic
    def makeConvs = new CoreConvs with ListConv with ASTConv
  }
  
  class MySubst requires TGeneric extends CGeneric with CSubstASTGeneric with SubstASTTC{
    def term = SubstAST ((x: Term) => {Console.println(x); x match { case Name(_) => Name("b") 
      case _ => FineGrained.makeConvs.term2rep(x).rep(this).apply(x)}})
    def tpe = SubstAST ((x: Type) => {Console.println(x);x})
  }
  /*Severity and Description	Path	Resource	Location	Creation Time	Id
type mismatch;
 found   : deploySubst.this.CGeneric with deploySubst.this.CSubstASTGeneric with deploySubst.this.SubstASTTC with deploySubst.this.MySubst
 required: gm.open.FineGrained.TGeneric{override type g = ?}	GM/src/gm/open	opengm.scala	line 231	1158442354613	21859
*/
  type TGeneric = CGeneric with CSubstASTGeneric with SubstASTTC with MySubst
  def Generic = new  MySubst
  val term: Term = LocalVal("a", Some(Inst(Name("ccc"))), Name("a"), Name("eeee"))
  val gen = Generic; val c= makeConvs; import c._; 
  val r = gen.substAST(term) // 
}*/





/*
  

trait ShowBinComp requires (CoreConvsComp with GenericComp with ShowBinComp) {
  class ShowBinTC extends Generic[ShowBin] {
    def unit = ShowBin ((x: Unit) => Nil) 
    def plus[a, b](implicit c1: a=>Rep[a], c2: b=>Rep[b]) = ShowBin (
        (x: Plus[a, b]) => x match {
          case Inl(el) => _0 :: showBin(el)
          case Inr(el) => _1 :: showBin(el)
        }) 
    
    def pair[a, b](implicit c1: a=>Rep[a], c2: b=>Rep[b]) = ShowBin (
        (x: Pair[a, b]) => showBin(x._1) ::: showBin(x._2))
    
    def datatype[a, b](iso: Iso[a,b])(implicit c1: a=>Rep[a]) = ShowBin (
        (x: b) => showBin(iso.fromData(x)))
    
    def char = ShowBin ((x: Char) => bits(7,x))
    def int = ShowBin ((x: Int) => bits(16,x))

    def showBin[t](x: t)(implicit c: t=>Rep[t]): Bin = c(x).rep[ShowBin](self).apply(x) 
  }
  
  def ShowBin[aa](f: aa => Bin) = new ShowBin{type a=aa; val apply = f} 
  trait ShowBin extends TypeFun1{ val apply: a => Bin }

  type Bin = List[Bit]
  trait Bit
    case object _0 extends Bit
    case object _1 extends Bit
  def bits(n: Int, x: Int): Bin = if(n==0) Nil else {if((x&1)==1) _1 else _0} :: bits(n-1,x>>1)
}


*/
// testpad:
// {val sb = new ShowBin(); import sb.convs._; sb.showBin(3)}
// {val sb = new ShowBin(); import sb.convs._; sb.showBin(List(3,5))}
//{val sb = new ShowBin(); import sb.convs._; sb.showBin("Lisa".toList)}
//{val sb = new ShowBin(); import sb.convs._; sb.showBin("Lisa")} // --> string2seq is not chained with list2rep